from .que import KeeperQue
from .ext import ExtTitle,ExtSubTitle
import os

class DocNode:

    def __init__(self, file_path:str):
        self.vaild = False
        self.file_path = file_path
        self.filename = os.path.basename(file_path)
        # 验证路径的有效性
        if not os.path.exists(file_path):
            print("文件路径不存在")
            return
        # 提取文档内容
        self.title = ""
        self.sub_title = []
        self._load_doc()

    def __repr__(self) -> str:
        return f"""
        FilePath: {self.file_path}
        Vaild: {self.vaild}
        Title: {self.title}
        SubTitle: {self.sub_title}
        """
    
    def _load_doc(self):
        content = ""
        try:
            with open(self.file_path,"r",encoding="utf-8") as file:
                content = file.read()
        except Exception as e:
            print(f"DocNode load {self.file_path} error", e)
            self.vaild = False
            return
        # 提取文档内容
        self.title = ExtTitle(content)
        self.sub_title = ExtSubTitle(content)
        self.vaild = True
    
    def AttrFilePath(self):
        return self.file_path
    
    def AttrTitle(self):
        return self.title
    
    def AttrSubTitle(self) -> list[str]:
        return self.sub_title


class RelaDocCache:

    """
    相关文档缓冲对象
    """

    def __init__(self,related_path:str) -> None:
        self.related_path = related_path
        # map : doc-title --> DocNode
        self.doc_title_dict: dict[str,DocNode] = dict()
        self._auto_load()

    def SearchDoc(self,doc_title:str) -> DocNode:
        """
        搜索文档标题: 唯一搜索,确定性搜索
        """
        return self.doc_title_dict.get(doc_title,None)

    def _auto_load(self):
        # 依次加载目录下的相关文档
        doc_nodes = []
        try:
            # 获取related_path下的所有文件
            files = os.listdir(self.related_path)
            for file in files:
                # 拼凑出路径
                file_path = os.path.join(self.related_path, file)
                print(file_path)
                # 读取文件内容
                if os.path.isfile(file_path):
                    # 实例成DocNode对象
                    doc_node = DocNode(file_path)
                    if doc_node.vaild:
                        self.doc_title_dict[doc_node.title] = doc_node
                        print(doc_node)
                # elif os.path.isdir(file_path):
                #     # TODO: not support inner dir now
                #     pass
        except Exception as e:
            print("related doc file load down : ", e)
            self.doc_title_dict = dict() # clear



class RelaSubjectExtor:

    """
    相关文档的主题索引器

    构造说明: 请保证content内容能够提取得到主题

    输入: 
    1. 当前提供的文档内容
    2. 相关文档所在的关联目录
    
    步骤:
    1. 提取当前文档的标题以及内部的子主题
    2. 在相关文档中搜索匹配子主题的文档
    3. 提取匹配文档的标题以及子主题
    4. 递归搜索,建立树状关系索引
    """

    def __init__(self, related_dir:list[str]):
        self.related_dir: list[str] = related_dir
        # 加载并缓冲相关文档
        self.DocCache: list[RelaDocCache] = []
        self._load_related_docs()
    
    def _preload(self,rootdoc_file_path:str):
        # 初始化根文档
        self.rootDoc = DocNode(rootdoc_file_path)
        if self.rootDoc.vaild is False:
            raise Exception("root doc is failed")
        # debug
        print(self.rootDoc)
        # 提取文档的标题以及子主题
        self.title = self.rootDoc.AttrTitle()
        self.subtopics = self.rootDoc.AttrSubTitle()
    
    def SearchInTree(self, rootdoc_file_path:str) -> dict[str,DocNode]:
        """
        在文档关键词的缓冲池中进行递归搜索
        """
        # 预加载根文档
        self._preload(rootdoc_file_path)
        # 初始化搜索记录器:记录所搜索到的关键词对应的文档
        # map : title --> DocNode
        self.SearchKeeper: dict[str,DocNode] = dict()
        # 初始化查询队列
        self.Que = KeeperQue()
        for subtopic in self.subtopics:
            self.Que.Put(subtopic)
        # bfs 搜索
        try:
            while not self.Que.Empty():
                subtopic = self.Que.Get()
                # 递归搜索
                results = self._search_subtopic(subtopic)
                for doc in results:
                    # 记录当前的结果
                    self.SearchKeeper[doc.AttrTitle()] = doc
                    # 当前结果衍生的子节点全部入队
                    for title in doc.AttrSubTitle():
                        self.Que.Put(title)
        except Exception as e:
            print("bfs search error happen: ", e)
        # 返回搜索结果
        return self.SearchKeeper
    
    def _search_subtopic(self,subtopic:str) -> list[DocNode]:
        """
        从缓冲区的文档中所搜关键词
        """
        results: list[DocNode] = []
        for cache in self.DocCache:
            # 搜索文档
            res = cache.SearchDoc(subtopic)
            # 存储结果
            if res is not None:
                results.append(res)
                # break
        return results

    def _load_related_docs(self):
        """
        加载并缓冲相关文档
        """
        for dir in self.related_dir:
            print("cache dir :" , dir)
            docCache = RelaDocCache(dir)
            self.DocCache.append(docCache)


